//
//  String.h
//  Prism
//
//  Created by Bas du Pre on 20-05-11.
//  Copyright 2011 UU. All rights reserved.
//

#pragma once

#include <iostream>
#include <cstdarg>

#include "primitives.h"

namespace Prism {
    
    class String {
        
    public:
        String();
        
        String(const char *str);
        String(const String &str);
        String(const PFloat &floatVal);
        
        String(PInt n);
        String(char c);
        
        virtual ~String();
        
        String operator +(const String &rhs);
        String operator -(const String &rhs);
        
        bool operator ==(const String &rhs) const {
            return compare((*this).c_str(), rhs.c_str()) == 0;
        }
        
        bool operator !=(const String &rhs) const {
            return compare((*this).c_str(), rhs.c_str()) != 0;
        }
        
        bool operator >(const String &rhs) const {
            return compare((*this).c_str(), rhs.c_str()) == 1;
        }
        
        bool operator <(const String &rhs) const {
            return compare((*this).c_str(), rhs.c_str()) == -1;
        }
        
        bool operator >=(const String &rhs) const {
            return (rhs > *this || rhs == *this); 
        }
        
        bool operator <=(const String &rhs) const {
            return (rhs < *this || rhs == *this); 
        }
        
        String operator =(const String &rhs);
        
        String operator +=(const String &rhs);
        String operator -=(const String &str);
        
        char& operator [](PInt n) const {
            return String::at(n);
        }
        
        char& at(PInt n) const;
        
        String substr(PInt start, PInt end) const;
        String substr(PInt start) const;
        
        int find(String str, PInt pos = 0) const {
            return search((*this).c_str(), str.c_str(), pos);
        }
        
        int compare(const String &str) {
            return compare((*this).c_str(), str.c_str());
        }
        
        bool replace(const String &str, const String &str2);
        
        void replaceall(const String &str, const String &str2) {
            while(replace(str, str2)) ;
        }
        
        bool empty() const {
            return (*this).size() == 0;
        }
        
        void ltrim(char c);
        void rtrim(char c);
        void trim(const String &delim);
        
        void insert(const String &str, PInt pos);
        
        void erase(const String &str, PInt pos);
        
        bool erase(const String &str);
        
        void eraseall(const String &str) {
            while(erase(str)) ;
        }
        
        void reverse();
		
        void upper() {
            uppercase(szBuffer);
        }
        
        void lower() {
            lowercase(szBuffer);
        }
        
        void clear();
        
        int length() const {
            return getlen(szBuffer);
        }
        
        int size() const {
            return (*this).length();
        }
        
        int capacity() const {
            return (int)nBuffSize;
        }
        
        void reserve(PInt n);
        void resize(PInt n);
        
        void strip(const String &delim);
        
        void append(const String &str) {
            *this += str;
        }
        
        void assign(const String &str) {
            *this = str;
        }
        
        operator char*() { return szBuffer; }
        operator const char*() { return szBuffer; }
        
        const char* c_str() const {
            return szBuffer;
        }
        
        String mid(PInt start, PInt len) const {
            return (*this).substr(start, start + len);
        }
        
        String left(PInt len) const {
            return (*this).substr(0, len);
        }
        
        String right(PInt len) const {
            return (*this).substr((*this).length() - len, (*this).length());
        }
        
        friend std::ostream& operator <<(std::ostream &os, const String &str);
        friend std::istream& operator >>(std::istream &is, String &str);
        
        std::istream& getline(std::istream &is, String &str);
        
        int find_first_of(const String &str, PInt pos = 0) const;
        int find_first_not_of(const String &str, PInt pos = 0) const;
        int find_last_of(const String &str, PInt pos = 0) const;
        int find_last_not_of(const String &str, PInt pos = 0) const;
        
        static String fromFormat(String format, ...);
        static String fromFormatAP(String format, va_list ap);
        
        virtual String toString();
        
    private:
        int getlen(const char *str) const;
        void concat(char *str1, const char *str2);
        int compare(const char *str1, const char *str2) const;
        int search(const char *str, const char *str2, PInt pos) const;
        bool ispunc(char c, const String &delim);
        void uppercase(char *str);
        void lowercase(char *str);
        void copy(char *dest, const char *src);
        void allocate_memory(PInt n);
        void free_memory();
        void grow();
        
    private:
        char *szBuffer;
        size_t nBuffSize;
        
    };
    
}
